#include "trace.h"
#include <sys/mman.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>

#define USE_MMAP 1
#define USE_OP_POOL 1

#if USE_MMAP
static int fd = -1;
static void *fstart,*fend;
#else
static std::ifstream trace_stream;
#endif

#if USE_OP_POOL
#define OP_POOL_SIZE 4096
static OP op_pool[OP_POOL_SIZE];
static uint64_t free_id = 0;
#endif

static uint64_t op_id = 0;

void init_trace(std::string file_name)
{
#if USE_MMAP
    fd = open(file_name.c_str(), O_RDONLY);
    struct stat sb;
    fstat(fd,&sb);
    fstart = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
    fend = (void*)((uint64_t)fstart + sb.st_size);
#else
    trace_stream.open(file_name);
    assert(trace_stream.is_open());
#endif
}



OP *read_op()
{
#if USE_OP_POOL
    assert(OP_POOL_SIZE - (op_id - free_id) > 0);
    OP *op = &op_pool[op_id % OP_POOL_SIZE];
#else
    OP *op = new OP;
#endif

#if USE_MMAP
    if(fstart >= fend)
#else
    if (trace_stream.eof())
#endif
    {
        op->valid = false;
        op->trace = {0};
        op->id = op_id++;
        return op;
    }

#if USE_MMAP
    op->trace = *(Trace*)fstart;
    // memcpy(&op->trace,fstart, sizeof(Trace));
    fstart = (void*)((uintptr_t)fstart + sizeof(Trace));
#else
    trace_stream.read((char *)(&op->trace), sizeof(Trace));
#endif

    // op->trace.opcode = OP_ADD;
    // op->trace.src[0] = 1;
    // op->trace.src[1] = 1;
    // op->trace.dst = 1;
    // op->trace.branch_taken = false;
    // op->trace.pc = 0x80000000ul+op_id*4;

    op->id = op_id++;
    op->valid = true;
    return op;
}

void free_op(OP *op)
{
#if USE_OP_POOL
    assert(op->id == free_id);
    free_id++;
#else
    delete op;
#endif
}
